#include "Bot.h"

using namespace std;


Bot::Bot()
{
  
}

//plays a single game of Ants.
void Bot::playGame()
{
  //state._general.create();
  //reads the game parameters and sets up
  cin >> state;
  state.setup();
  endTurn();

  
  state._general.initialize();

  //continues making moves while the game is not over
  while(cin >> state)
  {
    
    state._general.reconnaissance();
    state.bug << "after reconnaissance " << std::endl;
    state._general.show( state.bug.file );
    // Перемещаем всех муравьев 
    state._general.make_move();
    state.bug << "after make_move " << std::endl;
    state._general.show( state.bug.file );
    state._general.finalize();
    endTurn();
  }
};

//finishes the turn
void Bot::endTurn()
{
    if(state.turn > 0)
        state.reset();
    state.turn++;

    cout << "go" << endl;
};


void find_food(State& s, const std::vector<std::vector<Square> >& grid, std::vector<Location>& food )
{
  s.bug << "find_food!!" << std::endl;
  Location loc;
  std::vector< std::vector<Square> >::const_iterator itr1 = grid.begin();
  for ( loc.row = 0; itr1 != grid.end(); ++itr1, ++loc.row)
  {
    std::vector<Square>::const_iterator itr2 = itr1->begin();
    for ( loc.col=0; itr2 != itr1->end(); ++itr2, ++loc.col )
    {
      if (itr2->isFood)
      {
        s.bug << "FOOD!! " << loc.row << " " << loc.col << std::endl;
        food.push_back(loc);
      }
    }
  }
}

Location near_food(State& s, Location loc, const std::vector<Location>& food )
{
  if (food.empty()) return Location();
  Location near = food[0];
  if (food.size()==1) return near;
  std::vector<Location>::const_iterator itr = food.begin();
  double distance = s.distance(loc, near);
  s.bug << "best " << distance << std::endl;
  for ( ++itr ; itr!= food.end(); ++itr)
  {
    double current = s.distance(loc, *itr);
    s.bug << "current " << current <<" :" << itr->row << "," << itr->col << std::endl;
    if ( current < distance)
    {
      distance = current;
      near = *itr;
      s.bug << "best " << distance << std::endl;
    }
  }
  s.bug << "near " << distance <<" :" << near.row << "," << near.col << std::endl;
  return near;
}

// const int DIRECTIONS[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };      //{N, E, S, W}  //{вниз, вправо, вверх, влево}
int select_direction(Location from, Location to)
{
  int row = from.row - to.row;
  int col = from.col - to.col;
  
  if ( std::abs(row) > std::abs(col) )
    return row > 0 ? 0 : 2;
  else
    return col > 0 ? 3 : 1;
}

class wave_alg
{
  State& state;
  Location target;
  //Location to;
  
  std::vector<std::vector<int> > grid;

public:
  int wave;
  int direct;


  /*
  int direct()
  {
    int w = 100000;
    Location dloc = target;
    if ( target.row > 0 )
    {
      grid[target.row-1]
    }
  }
  */
  
  wave_alg(State& state/*, Location to*/ )
    : state(state)
    //, to(to)
    , wave(0)
  {
    grid = vector<vector<int> >(state.rows, vector<int>(state.cols, -1));
  }


  void block_radius(Location t, double r)
  {
    state.bug << "block_radius" << std::endl;
    int fr = t.row - r;
    int tr = t.row + r;
    int fc = t.col - r;
    int tc = t.col + r;

    for ( int i = fr; i <= tr; ++i)
    {
      for ( int j = fc; j <= tc; ++j)
      {
        int row = i;
        if (row < 0) row += state.rows;
        if (row >= state.rows ) row -= state.rows;
        int col = j;
        if (col < 0) col += state.cols;
        if (col >= state.cols ) col -= state.cols;
        
        if (state.distance(t, Location(row, col) ) <= r  )
        {
            grid[row][col] = 0;
            state.bug << "BLOCKED" << std::endl;
        }
      }
    }
  }
  void setup(Location t)
  {
    target = t;
    wave = 1;
    direct = -1;
    
    int food_count = 0;

    for ( int i = 0; i < state.rows; ++i)
    {
      for ( int j = 0; j < state.cols; ++j)
      {
        Square s = state.grid[i][j];
        ///    bool isVisible, isWater, isHill, isFood;
        /// int ant, hillPlayer;
        if ( s.isWater /*|| s.isHill*/ || s.ant== 0 /*|| s.hillPlayer!=-1*/)
          grid[i][j] = 0;
        else if ( s.ant > 0 )
        {
          grid[i][j] = 0;
          //grid[i][j] = 1;
          // block_radius( Location(i,j), state.attackradius * 2 );
        }
        else if ( s.isFood || ( s.isHill && s.hillPlayer > 0 ) )
        {
          //direct = -1;
          grid[i][j] = 1;
          food_count++;
        }
        else 
          grid[i][j] = -1;

        /*
        if ( grid[i][j] < 0 )
          state.bug << ".";
        else
          state.bug << grid[i][j];
        */
      }
      //state.bug << std::endl;
    }

    if ( food_count == 0 )
    {
      if ( grid[0][0] == -1 )
        grid[0][0] = 1;

      if ( grid[state.rows-1][state.cols-1] == -1 )
        grid[state.rows-1][state.cols-1] = 1;

      if ( grid[state.rows-1][0] == -1 )
        grid[state.rows-1][0] = 1;

      if ( grid[0][state.cols-1] == -1 )
        grid[0][state.cols-1] = 1;

}
    //state.bug << "SETUP" << wave << std::endl;
  }

  void show(Location t)
  {
    for ( int i = 0; i < state.rows; ++i)
    {
      for ( int j = 0; j < state.cols; ++j)
      {
        if ( i == t.row && j==t.col )
          state.bug << "@";
        else if ( grid[i][j] < 0 )
          state.bug << ".";
        else if ( grid[i][j] > 9 )
          state.bug << "^";
        else if ( grid[i][j] == 0 )
          state.bug << "#";
        else
          state.bug << grid[i][j];
      }
      state.bug << std::endl;
    }
    state.bug << std::endl;
  }
  bool dowave()
  {
    for ( int i = 0; i < state.rows; ++i)
    {
      for ( int j = 0; j < state.cols; ++j)
      {
        if ( mark(i, j) )
          return true;
      }
    }

    ++wave;
    return false;
  }

  void dowave2()
  {
    for ( int i = 0; i < state.rows; ++i)
    {
      for ( int j = 0; j < state.cols; ++j)
      {
        mark2(i, j);
      }
    }

    ++wave;
  }

  void mark2(int row, int col)
  {
    if ( grid[row][col]!=wave )
      return;

    if (row > 0 )
    {
      if ( grid[row-1][col] == -1 || ( grid[row-1][col] > wave + 1 ) )
        grid[row-1][col] = wave + 1;
    }
    else if ( row == 0 )
    {
      if ( grid[state.rows-1][col] == -1 || ( grid[state.rows-1][col] > wave + 1 ) )
        grid[state.rows-1][col] = wave + 1;
    }

    if (row < state.rows-1 )
    {
      if ( grid[row+1][col] == -1 || ( grid[row+1][col] > wave + 1 ))
        grid[row+1][col] = wave + 1;
    }
    else if ( row == state.rows-1 )
    {
      if ( grid[0][col] == -1 || ( grid[0][col] > wave + 1 ) )
        grid[0][col] = wave + 1;
    }

    if (col > 0 )
    {
      if ( grid[row][col-1] == -1 || ( grid[row][col-1] > wave + 1 ) )
        grid[row][col-1] = wave + 1;
    }
    else if ( col == 0 )
    {
      if ( grid[row][state.cols-1] == -1 || ( grid[row][state.cols-1] > wave + 1 ))
        grid[row][state.cols-1] = wave + 1;
    }

    if (col < state.cols-1 )
    {
      if ( grid[row][col+1] == -1 || ( grid[row][col+1] > wave + 1 ))
        grid[row][col+1] = wave + 1;
    }
    else if ( col == state.cols-1 )
    {
      if ( grid[row][0] == -1 || ( grid[row][0] > wave + 1 )) 
        grid[row][0] = wave + 1;
    }
  }

  void reset_cell( int row, int col, int d )
  {
    switch (d)
    {
      case 0: --row; break;
      case 1: --col; break;
      case 2: ++row; break;
      case 3: ++col; break;
    };
    if ( row < 0 ) row  = state.rows - 1;
    if ( col < 0 ) col  = state.cols - 1;
    if ( row == state.rows ) row  = 0;
    if ( col == state.cols ) col  = 0;
    grid[row][col] = 0;
  }

  int get_top(int row, int col)
  {
    if (row == 0) row = state.rows-1;
    else --row;
    return grid[row][col];
  }

  int get_bottom(int row, int col)
  {
    if (row == state.rows-1) row = 0;
    else ++row;
    return grid[row][col];
  }

  int get_left(int row, int col)
  {
    if (col == 0) col = state.cols-1;
    else --col;
    return grid[row][col];
  }
  
  int get_right(int row, int col)
  {
    if (col == state.cols-1) col = 0;
    else ++col;
    return grid[row][col];
  }

  int get_direction( int row, int col )
  {
    int top = get_top(row, col);
    int bottom = get_bottom(row, col);
    int left = get_left(row, col);
    int right = get_right(row, col);

    
    state.bug << "top=" << top << std::endl;
    state.bug << "bottom=" << bottom << std::endl;
    state.bug << "left=" << left << std::endl;
    state.bug << "right=" << right << std::endl;
    // int d = -1;
    
    int magic = 1000000;

    if ( top == 0 ) top = magic;
    if ( bottom == 0 ) bottom = magic;
    if ( left == 0 ) left = magic;
    if ( right == 0 ) right = magic;
    
    if ( top > 0 && top <= bottom && top <= left && top <= right )
      return 0;

    if ( bottom > 0 && bottom <= top && bottom <= left && bottom <= right )
      return 2;

    if ( left > 0 && left <= top && left <= bottom && left <= right )
      return 3;

    if ( right > 0 && right <= top && right <= bottom && right <= left )
      return 1;


    if ( top!=magic) return 0;
    if ( bottom!=magic) return 2;
    if ( left!=magic) return 3;
    if ( right!=magic) return 1;

    return -1;
  }

  bool mark(int row, int col)
  {
    if ( grid[row][col]!=wave )
      return false;

    // const int DIRECTIONS[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };      //{N, E, S, W}  //{вниз, вправо, вверх, влево}
                                                                               // 0  1  2  3
    //{N, E, S, W}  //{вниз, вправо, вверх, влево}
    if (row > 0 )
    {
      if ( target.row == row-1 && target.col== col)
      {
        direct = 2;
        return true;
      }
      if ( grid[row-1][col] == -1)
        grid[row-1][col] = wave + 1;
    }

    if (row < state.rows-1 )
    {
      if ( target.row == row+1 && target.col== col)
      {
        direct = 0;
        return true;
      }
      if ( grid[row+1][col] == -1)
        grid[row+1][col] = wave + 1;
    }

    if (col > 0 )
    {
      if ( target.row == row && target.col== col-1)
      {
        direct = 1;
        return true;
      }
      if ( grid[row][col-1] == -1)
        grid[row][col-1] = wave + 1;
    }

    if (col < state.cols-1 )
    {
      if ( target.row == row && target.col== col+1)
      {
        direct = 3;
        return true;
      }
      if ( grid[row][col+1] == -1)
        grid[row][col+1] = wave + 1;
    }
    return false;
  }
};

void Bot::do_level0()
{
  /*
  state._bm_for_wm_food.show(state.bug.file, "for_wm_food");
  if ( !state._wm_food)
  {
    for (int i = 0 ; i < 50 && !state._wm_food; ++i)
      state._wm_food.drive_wave();
  }
  
  for( int ant=0; ant<(int)state.myAnts.size(); ant++)
  {
    if ( state.timer.getTime() > state.turntime - state.turntime/10 )
    {
      state.bug << "TIMEOUT " << state.timer.getTime() << " "  << state.turntime << endl;
      return;
    }
    //state.bug << "---------------------- ANT " << ant << endl;
    Location loc = state.myAnts[ant];
    int d = state._wm_food.direction(loc.row, loc.col);
    if ( d >= 0 )
    {
      Location loc2 = state.getLocation(state.myAnts[ant], d);
      
      
        if( state.grid[loc2.row][loc2.col].isWater
            || state.grid[loc2.row][loc2.col].ant != -1 )
        {
          d = -1;
          //state.bug << "---------------------- BEGIN d-1 " << ant << endl;
        }
        
        if (d == -1 )
        {
          //state.bug << "---------------------- Начинаем перебор " << ant << endl;
          bool flag = false;
          for( d=0; d<TDIRECTIONS; d++)
          {
            loc2 = state.getLocation(state.myAnts[ant], d);

            if( !state.grid[loc2.row][loc2.col].isWater
               && state.grid[loc2.row][loc2.col].ant == -1)
              
            {
              flag = true;
              break;
            }
          }
          if (!flag)
            d = -1;
          
        }
        
        if (d!=-1)
          state.makeMove(loc, d);
    }
    else
    {
      //state.bug << "ANT " << ant << " IDLE" << endl;
    }
  }
  */
}

void Bot::do_level1()
{
  //state.bug << "DO LEVEL 2" << endl;
  /*
  state._wm_food.reset();
  std::vector<Location>::iterator locItr;

  if ( state.turn % 4 == 0 )
  {

  
  locItr = state.enemyAnts.begin();
  for ( ;locItr != state.enemyAnts.end(); ++locItr)
    state._wm_food( locItr->row, locItr->col, 1 );

  locItr = state.food.begin();
  for ( ;locItr != state.food.end(); ++locItr)
    state._wm_food( locItr->row, locItr->col, 1 );
  
  locItr = state.enemyHills.begin();
  for ( ;locItr != state.enemyHills.end(); ++locItr)
    state._wm_food( locItr->row, locItr->col, 1 );

  }

//std::vector<Location> myAnts, enemyAnts, myHills, enemyHills, food;
  
  if ( !state._wm_food)
  {
    for (int i = 0 ; i < 10 && !state._wm_food; ++i)
      state._wm_food.drive_wave();
  }
  
  std::vector<location>::iterator itr = state.troops.begin();
  for ( ; itr!=state.troops.end(); ++itr)
  {
    int d = state._wm_food.direction(itr->row, itr->col);
    if (d != -1)
    {
      //if ( state.turn % 4 == 0 )
      {
        Location loc2 = state.getLocation(Location( itr->row, itr->col ), d);
        
        if( state.grid[loc2.row][loc2.col].isWater)
          d = -1;
        
        if (d == -1 )
        {
          bool flag = false;
          for( d=0; d<TDIRECTIONS; d++)
          {
            loc2 = state.getLocation(Location( itr->row, itr->col ), d);
            if( !state.grid[loc2.row][loc2.col].isWater)
            {
              flag = true;
              break;
            }
          }
          if (!flag)
            d = -1;
        }
        if (d!=-1)
          *itr = state.getLocation( Location( itr->row, itr->col ), d);
      }
      //state._wm_food( itr->row, itr->col, 1 );
    }
  }

  state._wm_food.reset();
  itr = state.troops.begin();
  for ( ; itr!=state.troops.end(); ++itr)
    state._wm_food( itr->row, itr->col, 1 );
  
  do_level0();
  */

}


//makes the bots moves for the turn
void Bot::makeMoves()
{
    state.bug << "turn " << state.turn << ":" << endl;
    state.bug << state << endl;
    
    // myHills
    
    
    
    if ( false && state.myAnts.size() / 4 >= state.troops.size() )
    {
      if ( !state.myHills.empty() && state.troops.size() < 10 )
      {
        state.troops.push_back( location(state.myHills[ state.turn % state.myHills.size() ]) );
        state.bug << "РОЖДЕНИЕ " << state.troops.size()<< endl;
      }
      
      std::sort(state.troops.begin(), state.troops.end());
      std::vector<location>::iterator it = std::unique(state.troops.begin(), state.troops.end()); // 10 20 30 20 10 ?  ?  ?  ?
      state.troops.resize( it - state.troops.begin() ); 
    }
    
    
    if ( state.troops.empty() )
      do_level0();
    else
      do_level0();
    
    /*
    switch(state.level)
    {
      case State::level0 : do_level0(); break;
      case State::level1 : do_level0(); break;
      default: do_level0(); break;
    }
    */
    

    state.bug << "time taken: " << state.timer.getTime() << "ms" << endl << endl;
    
    
    return;
    
    //state._bitmap.show(state.bug.file);
    /*
    state._bm_water.show(state.bug.file, "water");
    state._bm_my_hills.show(state.bug.file, "my hills");
    state._bm_enemy_hills.show(state.bug.file, "enemy hills");
    state._bm_my_ants.show(state.bug.file, "my ants");
    state._bm_enemy_ants.show(state.bug.file, "enemy ants");
    state._bm_food.show(state.bug.file, "food");
    */

    
    //state._bm_for_wm_food.show(state.bug.file, "for_wm_food");
    
    /*
    if ( !state._wm_food)
    {
      for (int i = 0 ; i < 100 && !state._wm_food; ++i)
        state._wm_food.drive_wave();
    }
    state._wm_food.show(state.bug.file, "food");
    */
    


    /*
    wave_alg alg(state);

    alg.setup(Location());
    for (int i = 0 ; i < 100; ++i)
      alg.dowave2();
    */

    for( int ant=0; ant<(int)state.myAnts.size(); ant++)
    {
      state.bug << "---------------------- ANT " << ant << endl;
      Location loc = state.myAnts[ant];
      int d = 0; //state._wm_food.direction(loc.row, loc.col);
      //int d = alg.get_direction(loc.row, loc.col);
      if ( d >= 0 )
      {
        state.bug << "---------------------- READY d= " << d << ant << endl;
        Location loc2 = state.getLocation(state.myAnts[ant], d);
        if( state.grid[loc2.row][loc2.col].isWater
            || state.grid[loc2.row][loc2.col].ant != -1 )
        {
          d = -1;
          state.bug << "---------------------- BEGIN d-1 " << ant << endl;
        }
        
        if (d == -1 )
        {
          state.bug << "---------------------- Начинаем перебор " << ant << endl;
          bool flag = false;
          for( d=0; d<TDIRECTIONS; d++)
          {
            loc2 = state.getLocation(state.myAnts[ant], d);

            if( !state.grid[loc2.row][loc2.col].isWater
               && state.grid[loc2.row][loc2.col].ant == -1)
              
            {
              flag = true;
              break;
            }
          }
          if (!flag)
            d = -1;
          
        }
        
        if (d!=-1)
          state.makeMove(loc, d);
        //alg.reset_cell( loc.row, loc.col, d );
      }
      else
      {
        state.bug << "ANT " << ant << " IDLE" << endl;
        //alg.show(loc);
      }
    }
    /*
    std::vector<Location> food;
    find_food( state, state.grid, food); 
    wave_alg alg(state);
    for( int ant=0; ant<(int)state.myAnts.size(); ant++)
    {
      
      if ( !food.empty() )
      {
        alg.setup(state.myAnts[ant]);
        for (int i = 0 ; i < 100; ++i)
        {
          if ( alg.dowave() ) 
          {
            //state.bug << "WAVE READY " << alg.wave << std::endl;
            break;
          }
        }
        if ( alg.direct != -1 )
        {
          //state.bug << "FOOD direct " << alg.direct << std::endl;
          state.makeMove(state.myAnts[ant], alg.direct );
          continue;
        }
      }
      
        for(int d=0; d<TDIRECTIONS; d++)
        {
            Location loc = state.getLocation(state.myAnts[ant], d);

            if(!state.grid[loc.row][loc.col].isWater
               && ( state.grid[loc.row][loc.col].ant == -1
                      && state.grid[loc.row][loc.col].hillPlayer == -1 )
            )
            {
                state.makeMove(state.myAnts[ant], d);
                break;
            }
        }
    }
    */

    state.bug << "time taken: " << state.timer.getTime() << "ms" << endl << endl;
};

